/**
 * Tree管理
 * 1、通过id获取名称
 * 2、通过id获取儿子
 * 3、通过id获取父亲
 * 4、通过id获取儿子....孙子
 * 5、通过id获取到根级别
 * 6、通过id获取孩子条数
 * ...
 */

const Tree = (function () {
    let treeList = [] // 原始列表
    let treeMap = {} // map
    return class TreeManage {
        /**
         * 获取初始化
         * @param {Array} list
         * @param {Object} options
         * @param {String} options.id idkey
         * @param {String} options.parentId 父亲idkey
         * @param {String} options.name 名称key
         * @param {String} options.children 子集key
         */
        constructor(list, { id, parentId, name, children }) {
            // 字段别名
            this.fieldAlias = {
                id: id || 'id',
                parentId: parentId || 'parentId',
                name: name || 'name',
                children: children || 'children'
            }

            this.init(list) // 初始化
        }

        /**
         * 初始化
         */
        init(list) {
            const { options } = this
            treeList = this._toList(list) //tree转为list
            treeMap = this._toMap(treeList) // tree转为map
        }

        /**
         * 获取祖级别
         * @param {String} findId
         */
        getParentsById(findId, format) {
            let resList = []
            const { id, parentId } = this.fieldAlias
            for (let i = 0, len = treeList.length; i < len; i++) {
                const cur = treeList[i]
                if (cur[id] === findId) {
                    const itemFormat = format ? format(cur) : cur
                    resList.push(itemFormat)

                    // 是否存在父级
                    const pid = cur[parentId]
                    if (pid && treeMap[pid]) {
                        const parents = this.getParentsById(pid, format)
                        resList = parents.concat(resList)
                    }
                }
            }
            return resList
        }

        /**
         * 通过id获取名称
         * @param {Number|String} findId
         * @param {String} name
         */
        getNameById(findId) {
            const { name } = this.fieldAlias
            return treeMap[findId] ? treeMap[findId][name] : null
        }

        /**
         * 通过id列表获取名称
         * @param {Number|String} findId
         * @param {Object} nameMap
         */
        getNameByIdList() {
            const fieldIdList = [...arguments]
            return fieldIdList.reduce(
                (wrap, id) => {
                    const name = this.getNameById(id)
                    wrap.list.push(name)
                    wrap.map[id] = name
                    return wrap
                },
                {
                    list: [],
                    map: {}
                }
            )
        }

        /**
         * 是否存在子集
         * @param {String|Number} findId
         * @return {Boolean} res
         */
        hasChild(findId) {
            const { parentId } = this.fieldAlias
            const findIdx = treeList.findIndex(itm => itm[parentId] === findId)
            return findIdx !== -1
        }

        /**
         * 通过id获取孩子
         * @param {String|Number} findId 查询id
         * @return {Array|Null}
         */
        getChildrenById(findId) {
            const { id, children } = this.fieldAlias
            for (let i = 0, len = treeList.length; i < len; i++) {
                const cur = treeList[i]
                if (cur[id] === findId) {
                    if (this.hasChild(cur[id])) {
                        return cur[children]
                    }
                }
            }
            return null
        }

        /**
         * 获取孩子个数
         * @param {String|Number} findId 查找的ID
         * @return {Number} count
         */
        getChildSize(findId) {
            const { parentId, children } = this.fieldAlias
            if (!treeMap[findId]) return 0
            const child = treeMap[findId][children]
            return Array.isArray(child) ? child.length : 0
        }

        /**
         * tree转为list
         * @param {Array} list tree转为list
         * @return {Array}
         */
        _toList(list) {
            let resList = []
            const { children } = this.fieldAlias
            for (let i = 0, len = list.length; i < len; i++) {
                const itm = list[i]
                resList.push(itm)
                // 是否存在子集
                if (Array.isArray(itm[children]) && itm[children].length) {
                    const chilrenList = this._toList(itm[children])
                    resList = resList.concat(chilrenList)
                }
            }
            return resList
        }

        /**
         * list转为map
         * @param {Array} list
         * @return {Object}
         */
        _toMap(list) {
            if (!Array.isArray(list)) return {}
            const { id } = this.fieldAlias
            return list.reduce((res, cur) => {
                const idVal = cur[id]
                res[idVal] = cur
                return res
            }, {})
        }
    }
})()
